asyncapi: '3.0.0'

info:
  title: Audit Trail Service
  version: '1'
  description: |
    The Audit Trail service maintains a unified, searchable record of actions taken across
    Plumery and integrated third-party systems. It ingests access logs from Plumery's
    ingress gateway for actions performed within Plumery, and accepts events published
    directly by non-Plumery services for actions that happen outside Plumery's boundary.
    Both are stored side by side, tagged by origin (internal vs external), and made
    queryable through the audit-trail-api

defaultContentType: application/json

servers:
  kafka:
    host: localhost:9092
    protocol: kafka

channels:
  audit.event.external:
    address: audit.event.external
    messages:
      ExternalEventReportedEvent:
        $ref: '#/components/messages/ExternalEventReportedEvent'

operations:
  ExternalEventReported:
    action: receive
    channel:
      $ref: '#/channels/audit.event.external'

components:
  messages:
    ExternalEventReportedEvent:
      name: ExternalEventReported
      title: External Event Reported
      summary: Event reported by a non-Plumery service to be recorded in the shared audit trail
      description: |
        Event published by a non-Plumery service to record an action in the shared audit trail,
        alongside entries generated from actions taken inside Plumery

        ### How to Publish Audit Events from External Services

        #### Overview
        By default, Plumery's audit trail captures all user interactions (HTTP requests) coming into
        Plumery services

        Audit trail also supports events coming from non-Plumery services. To enable this, the bespoke
        service needs to send an `ExternalEventReported` event for every request

        This is useful when:
        * The action is performed entirely outside Plumery (e.g. by a partner or bespoke service)
        * You need the action to be queryable and exportable through the same `audit-trail-api` used
        for Plumery-native audit entries
        * You want the event clearly attributed to its originating service, distinct from Plumery's
        own access-log entries

        #### How It Works
        You publish a CloudEvents-compatible Avro record to the dedicated topic `audit.event.external`.
        Once received, the audit-trail service will:
        1. Validate the event against the `ExternalEventReported` schema
        2. Persist it, tagged with `origin: EXTERNAL` and the publishing `eventSource`
        3. Make it queryable and exportable via the existing `audit-trail-api` search/export endpoints,
        filterable by source

        Events that fail schema validation are routed to the `audit.dlq` dead-letter topic instead of being recorded

        #### Event Payload Structure
        ```json
        {
          "id": "a1cc063a-76b0-4a88-a60f-2f640a859b0e",
          "eventSource": "partner-payments-service",
          "type": "com.partner.payments.PaymentInitiated",
          "time": 1779119676000,
          "action": "PaymentInitiated",
          "description": "Payment initiated by partner",
          "userId": "partner-service-user-42",
          "partyId": null,
          "staffId": null,
          "staffRoles": null,
          "userLocation": null,
          "userAgent": null,
          "sessionId": null,
          "apiRequest": null,
          "responseStatusCode": 200,
          "responseStatus": "OK",
          "metadata": "{\"correlationId\":\"c1a2b3\"}",
          "payload": "{\"amount\":100,\"currency\":\"USD\"}"
        }
        ```

        #### Field Reference
        * **id** - Unique event identifier, assigned by the publisher
        * **eventSource** - Identifies who/what the event is about: the publishing service name,
        or a business resource identifier such as `payment:6878951b-256b-4baa-9e81-ad4c577adc4e`
        * **type** - Event type, e.g. `com.partner.payments.PaymentInitiated`
        * **time** - When the action occurred, as milliseconds since the Unix epoch, e.g. `1779119676000`
        * **action** - What happened, e.g. `PaymentInitiated`
        * **description (optional)** - Human-readable description of the action
        * **userId / partyId / staffId (optional)** - Identifiers of the acting end-user,
        party or staff member, if known to the publisher
        * **staffRoles (optional)** - Roles of the acting staff member, if applicable
        * **userLocation / userAgent / sessionId (optional)** - Context of the acting client, if known
        * **apiRequest (optional)** - Details of the API request that triggered the action
        (`requestId`, `uri`, `httpMethod`, `requestBody`), if applicable
        * **responseStatusCode / responseStatus (optional)** - HTTP response outcome of the action, if applicable
        * **metadata (optional)** - Free-form JSON-encoded context
        * **payload (optional)** - Free-form JSON-encoded payload

        _Note: masking of sensitive data (e.g. PII, card numbers) is the publisher's responsibility — the audit-trail
        service stores `metadata` and `payload` as provided_
      payload:
        $ref: '#/components/schemas/ExternalEventReported'

  schemas:
    ExternalEventReported:
      schemaFormat: 'application/vnd.apache.avro;version=1.9.0'
      schema:
        $ref: './ExternalEventReported.avsc'